package com.xzzz.irda.guardcat.server.app;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.xzzz.common.base.pojo.R;
import com.xzzz.common.base.util.json.JsonUtil;
import com.xzzz.irda.guardcat.core.constants.MachineStatus;
import com.xzzz.irda.guardcat.server.GuardcatServerProperties;
import com.xzzz.irda.guardcat.server.alert.AbstractAlertManager;
import com.xzzz.irda.guardcat.server.app.pojo.GuardcatConfigRes;
import com.xzzz.irda.guardcat.server.app.pojo.MachineInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 【Server】应用与机器信息
 *
 * @author xzzz
 * @apiNote 由 expand-guardcat 模块提供的监控服务端API
 */
@Slf4j
@RestController
@RequestMapping("/guardcat")
public class GuardcatAppController {
    @Autowired
    private AppManager appManager;
    @Autowired
    private AbstractAlertManager alertManager;
    @Autowired
    private GuardcatServerProperties serverProperties;

    /**
     * 单个应用最大的 mock 机器数量
     */
    private static final int MAX_MOCK_MACHINE_COUNT_WITH_SINGLE_APP = 20;

    /**
     * 查询 Guardcat 配置
     */
    @GetMapping("/config")
    public R<GuardcatConfigRes> guardCatInfo() {
        GuardcatConfigRes res = new GuardcatConfigRes();
        res.setRepoType(serverProperties.getRepository().getType().name().toUpperCase());
        res.setFetchMachineInterval(serverProperties.getFetchMachineInterval());
        return R.ok(res);
    }

    /**
     * 应用列表
     *
     * @return 应用列表
     * @apiNote 获取全部应用
     */
    @GetMapping("/apps")
    public R<List<Map<String, Object>>> getApps() {
        List<Map<String, Object>> result = new ArrayList<>();
        appManager.getAppNames().forEach(appName -> {
            Map<String, Object> map = new HashMap<>(2);
            map.put("appName", appName);
            map.put("machines", appManager.getMachines(appName));
            result.add(map);
        });
        return R.ok(result);
    }

    /**
     * 应用与机器树状图
     *
     * @return 树状图
     */
    @GetMapping("/apps/tree")
    public R<List<Map<String, Object>>> getAppTree() {
        List<Map<String, Object>> result = new ArrayList<>();

        Collection<MachineInfo> machineAll = new ArrayList<>();

        // 全部所有机器信息
        appManager.getAppNames().forEach(appName -> machineAll.addAll(appManager.getMachines(appName)));

        log.debug("查询机器列表，当前在线，离线共[{}]台机器", machineAll.size());

        // 按应用转换为map, appName:List<machine>
        Map<String, List<MachineInfo>> machineMaps = machineAll.stream()
                .collect(Collectors.groupingBy(MachineInfo::getAppName));

        List<String> machineIds = new ArrayList<>();
        for (List<MachineInfo> value : machineMaps.values()) {
            machineIds.addAll(value.stream().map(MachineInfo::getMachineId).collect(Collectors.toList()));
        }

        // 查询全部机器的警告数
        Map<String, Long> alertCounts = alertManager.countMachine(machineIds, false);

        Set<String> appNames = appManager.getAppNames();

        appNames.forEach(appName -> {
            Map<String, Object> map = new HashMap<>(4);
            map.put("name", appName);
            map.put("appName", appName);
            map.put("appType", "app");

            // 对机器按环境排序
            List<MachineInfo> machineInfos = machineMaps.get(appName);
            if (CollUtil.isEmpty(machineInfos)) {
                return;
            }
            machineInfos = machineInfos.stream().sorted(Comparator.comparingInt(MachineInfo::getSort)).collect(Collectors.toList());
            List<Map<String, Object>> machines = new ArrayList<>(machineInfos.size());

            for (MachineInfo machineInfo : machineInfos) {
                HashMap<String, Object> machineVO = new HashMap<>(20);

                // 名称: 应用名称 [版本] [环境]
                machineVO.put("name", String.format("%s [%s] [%s] ", machineInfo.getHostName(),
                        machineInfo.getAppVersion(), machineInfo.getProfilesActive().toUpperCase()));

                machineVO.put("appName", machineInfo.getAppName());
                machineVO.put("appVersion", machineInfo.getAppVersion());
                machineVO.put("appType", machineInfo.getAppType());
                machineVO.put("hostName", machineInfo.getHostName());
                machineVO.put("ipPort", machineInfo.getIp() + ":" + machineInfo.getPort());
                machineVO.put("machineId", machineInfo.getMachineId());
                machineVO.put("envName", machineInfo.getProfilesActive());

                machineVO.put("startTime", machineInfo.getStartTime());
                machineVO.put("lastHeartbeatTime", DateUtil.date(machineInfo.getLastHeartbeatTime()));
                machineVO.put("runTime", machineInfo.getRunTime());
                machineVO.put("frameworks", machineInfo.getFrameworks());

                machineVO.put("alertCount", alertCounts.get(machineInfo.getMachineId()) == null
                        ? 0 : alertCounts.get(machineInfo.getMachineId()));
                machineVO.put("warnLogCount", 0);
                machineVO.put("errLogCount", 0);

                // 机器状态只包含在线和下线，警告状态需要根据 alertCount 自行判断
                machineVO.put("status", machineInfo.getMachineStatus());

                machines.add(machineVO);

                int mockMachineCount = RandomUtil.randomInt(5, MAX_MOCK_MACHINE_COUNT_WITH_SINGLE_APP);
                for (int i = 0; i < mockMachineCount; i++) {
                    machines.add(copyMachine(machineVO));
                }
            }
            map.put("children", machines);

            result.add(map);

        });
        return R.ok(result);
    }

    private HashMap<String, Object> copyMachine(HashMap<String, Object> machineVO) {
        HashMap<String, Object> demo = (HashMap<String, Object>) machineVO.clone();
        demo.put("machineId", demo.get("machineId") + "-DEMO-" + RandomUtil.randomStringUpper(10));
        demo.put("appVersion", "[演示]");
        demo.put("name", String.format("%s [演示] [%s] ", machineVO.get("appName"), machineVO.get("envName")));
        int status = RandomUtil.randomInt(0, 100);
        if (status < 80) {
            demo.put("alertCount", 0);
            demo.put("status", MachineStatus.ONLINE);
        } else if (status < 90) {
            demo.put("alertCount", 1);
            demo.put("status", MachineStatus.ONLINE);
        } else {
            demo.put("status", MachineStatus.OFFLINE);
        }
        return demo;
    }

    /**
     * 查询机器详情
     *
     * @param appName   应用名称
     * @param machineId 机器ID
     * @return 机器详情
     */
    @GetMapping("/machine")
    public R<Map<String, Object>> getMachine(String appName, String machineId) {
        MachineInfo machineInfo = appManager.getMachine(appName, machineId);
        Map<String, Object> map = JsonUtil.toMap(machineInfo);
        map.put("ipPort", machineInfo.getIp() + ":" + machineInfo.getPort());
        map.put("envName", machineInfo.getProfilesActive());
        map.put("status", machineInfo.getMachineStatus());
        // 查询全部机器的警告数
        long alertCount = alertManager.countMachine(machineInfo.getMachineId(), false);
        map.put("alertCount", alertCount);
        return R.ok(map);
    }

    /**
     * 删除无效应用
     */
    @DeleteMapping("/app")
    public R<?> removeApps() {
        appManager.removeApps();
        return R.ok();
    }

    /**
     * 删除无效机器信息
     */
    @DeleteMapping("/machine")
    public R<?> removeMachine() {
        log.debug("删除离线机器");
        appManager.removeMachine();
        return R.ok();
    }

}
